package high.concurrent.listener;

import com.rabbitmq.client.Channel;
import high.concurrent.config.CloseOrderMQConfig;
import high.concurrent.model.OrderMessage;
import high.concurrent.server.ProductOrderService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.io.IOException;

/**
 * 第一个springAMQP的监听者
 * 需要加@Component，mq监听者一般单独写一个类里面
 */
@Component
@RabbitListener(queues = CloseOrderMQConfig.QUEUE_NAME)
@Slf4j
public class OrderMQListener {


    @Autowired
    private ProductOrderService productOrderService;

    /**
     * 接收
     * 1. 重复消费，幂等性校验
     * 2. 高并发下如何保证安全(视情况加分布式锁)
     * @param orderMessage 消息内容，如果发送消息是个Object，那body类型就是指定的发送Object即可，能自己转型
     * @param message  消息的信息内容，比如标签，发送内容等， 注意导包org.springframework.amqp.core.Message
     */
    @RabbitHandler
    public void firstAmqpHandler(OrderMessage orderMessage, Message message, Channel channel) throws IOException {

        long deliveryTag = message.getMessageProperties().getDeliveryTag();
        System.err.println("消息内容： " + orderMessage);

        try {
            // 关单检测
            boolean result = productOrderService.checkProductTask(orderMessage);

            if(result){
                // 消息确认
                log.info("消息确认");
                channel.basicAck(deliveryTag, false);
            }else{
                // 消息拒绝， 并重入队列
                log.info("商品回退检验失败，重新入队: {}", orderMessage);
                channel.basicNack(deliveryTag, false, true);
            }
        } catch (IOException e) {
            // 消息拒绝， 并重入队列
            log.info("商品回退检验异常，重新入队: {}", orderMessage);
            channel.basicNack(deliveryTag, false, true);
        }

//        /**
//         * 消息确认
//         * @param deliveryTag   把这个标识Tag传过去
//         * @param multiple 第二个参数表示一条条确认， 不要堆到最后一起确认
//         */
//        channel.basicAck(deliveryTag, false);
//
//        /**
//         * 消息拒绝， 并重入队列
//         * @param deliveryTag   把这个标识Tag传过去
//         * @param multiple 第二个参数表示一条条确认， 不要堆到最后一起确认
//         * @param requeue 第三个参数表示是否重入队列，true表示重入队列重新消费
//         */
//        channel.basicNack(deliveryTag, false, true);
    }
}
